﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace COC.Graphics
{
	public class CommandLineEventArgs : EventArgs
	{
		public CommandLineEventArgs(string commandLine)
		{
			m_CommandLine = commandLine;
		}

		string m_CommandLine;
		public string CommandLine
		{
			get { return m_CommandLine; }
			set { m_CommandLine = value; }
		}
	}

	public delegate void CommandLineEventHandler(object sender, CommandLineEventArgs e);

	public class InternalConsole : IDisposable
	{
		#region .ctor

		private Game m_Game;
		private Texture2D m_Texture;
		private string[] m_Text = new string[50];
		private int m_CurrentTextIndex = 0;
		private Vector2 m_TextSize;
		private int m_nLinesToShow = 0;
		private SpriteFont m_Font;

		public InternalConsole(Game ownerGame)
		{
			m_Game = ownerGame;
			OwnerClientSizeChanged(null, null);
			ownerGame.Window.ClientSizeChanged += new EventHandler(OwnerClientSizeChanged);
		}
		#endregion

		#region Methods

		void OwnerClientSizeChanged(object sender, EventArgs e)
		{
			m_ConsoleRect = new Rectangle(0, 0, m_Game.Window.ClientBounds.Width, (int)(m_Game.Window.ClientBounds.Height * 0.625f));
		}

		public CommandLineEventHandler OnCommandLine = null;

		public void Initialize(SpriteFont font)
		{
			m_Texture = Texture2D.FromFile(m_Game.GraphicsDevice, "console.png");
			m_TextSize = font.MeasureString("A");
			m_Font = font;
			m_CurrentTextIndex = 1;
			m_Text[0] = ">>Console Initialized Successfully...";
			m_Text[1] = ">>";
		}

		public void Dispose()
		{
			m_Texture.Dispose();
		}

		public void WriteLine(string str)
		{
			if (m_Text[m_CurrentTextIndex] == ">>")
			{
				m_Text[m_CurrentTextIndex] = "  " + str;
			}
			else
			{
				m_CurrentTextIndex = (m_CurrentTextIndex + 1) % m_Text.Length;
				m_Text[m_CurrentTextIndex] = str;
			}

			m_CurrentTextIndex = (m_CurrentTextIndex + 1) % m_Text.Length;
			m_Text[m_CurrentTextIndex] = ">>";
		}

		int m_indexBackUp = 1;

		public void OnKeyDown(Keys keys, bool bShift)
		{
			if (m_Text[m_CurrentTextIndex] == null)
			{
				m_Text[m_CurrentTextIndex] = ">>";
			}
		
			if (keys == Keys.Enter)
			{
				m_indexBackUp = 1;
				string cmd = m_Text[m_CurrentTextIndex];
				m_CurrentTextIndex = (m_CurrentTextIndex + 1) % m_Text.Length;
				m_Text[m_CurrentTextIndex] = ">>";
				if (OnCommandLine != null)
				{
					cmd = cmd.Substring(2);
					OnCommandLine(this, new CommandLineEventArgs(cmd));
				}
			}
			else if(keys == Keys.Up && bShift)
			{
				string str = m_Text[GetTextIndex(m_CurrentTextIndex - (m_indexBackUp++))];
				if(str != null && str.Length > 2)
				{
					m_Text[m_CurrentTextIndex] = str;
				}
			}
			else
			{
				m_indexBackUp = 1;
				if(keys == Keys.Back)
				{
					if(m_Text[m_CurrentTextIndex].Length > 2)
					{
						m_Text[m_CurrentTextIndex] =
							m_Text[m_CurrentTextIndex].Substring(
							0, m_Text[m_CurrentTextIndex].Length - 1);
					}
					return;
				}
				string str = KeyToChar(keys, bShift);
				if (str != "`")
				{
					m_Text[m_CurrentTextIndex] += str.ToString();
				}
			}
		}


		public static string KeyToChar(Keys key, bool shiftPressed)
		{
			// If key will not be found, just return space
			char ret = ' ';
			int keyNum = (int)key;
			if (keyNum >= (int)Keys.A && keyNum <= (int)Keys.Z)
			{
				if (shiftPressed)
					ret = key.ToString()[0];
				else
					ret = key.ToString().ToLower()[0];
			}
			else if (keyNum >= (int)Keys.D0 && keyNum <= (int)Keys.D9 &&
				shiftPressed == false)
			{
				ret = (char)((int)'0' + (keyNum - Keys.D0));
			}
			else if (key == Keys.D1 && shiftPressed)
				ret = '!';
			else if (key == Keys.D2 && shiftPressed)
				ret = '@';
			else if (key == Keys.D3 && shiftPressed)
				ret = '#';
			else if (key == Keys.D4 && shiftPressed)
				ret = '$';
			else if (key == Keys.D5 && shiftPressed)
				ret = '%';
			else if (key == Keys.D6 && shiftPressed)
				ret = '^';
			else if (key == Keys.D7 && shiftPressed)
				ret = '&';
			else if (key == Keys.D8 && shiftPressed)
				ret = '*';
			else if (key == Keys.D9 && shiftPressed)
				ret = '(';
			else if (key == Keys.D0 && shiftPressed)
				ret = ')';
			else if (key == Keys.OemTilde)
				ret = shiftPressed ? '~' : '`';
			else if (key == Keys.OemMinus)
				ret = shiftPressed ? '_' : '-';
			else if (key == Keys.OemPipe)
				ret = shiftPressed ? '|' : '\\';
			else if (key == Keys.OemOpenBrackets)
				ret = shiftPressed ? '{' : '[';
			else if (key == Keys.OemCloseBrackets)
				ret = shiftPressed ? '}' : ']';
			else if (key == Keys.OemSemicolon)
				ret = shiftPressed ? ':' : ';';
			else if (key == Keys.OemQuotes)
				ret = shiftPressed ? '"' : '\'';
			else if (key == Keys.OemComma)
				ret = shiftPressed ? '<' : ',';
			else if (key == Keys.OemPeriod)
				ret = shiftPressed ? '>' : '.';
			else if (key == Keys.OemQuestion)
				ret = shiftPressed ? '?' : '/';
			else if (key == Keys.OemPlus)
				ret = shiftPressed ? '+' : '=';

			// Return result

			//未能转换的符号
			if(key != Keys.Space && ret == ' ')
			{
				return "";
			}

			return ret.ToString();
		}

		#endregion

		#region Properties
		private bool m_bActivated = false;
		public bool Activate
		{
			get { return m_bActivated; }
			set { m_bActivated = value; }
		}

		Rectangle m_ConsoleRect;
		public int Width
		{
			get { return m_ConsoleRect.Width; }
			set { m_ConsoleRect.Width = value; }
		}

		public int Height
		{
			get { return m_ConsoleRect.Height; }
			set { m_ConsoleRect.Height = value; }
		}

		private byte m_Transparency = 100;
		public byte Transparency
		{
			get { return m_Transparency; }
			set { m_Transparency = value; }
		}

		#endregion

		public void Draw(SpriteBatch sprite)
		{
			if (!m_bActivated)
				return;
			sprite.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.SaveState);
			DrawConsoleBackGroundQuad(sprite);
			DrawTextLines(sprite, 0.0f);
			sprite.End();
		}

		private void DrawConsoleBackGroundQuad(SpriteBatch sprite)
		{
			sprite.Draw(m_Texture, m_ConsoleRect, new Color(Color.Black, m_Transparency));
		}

		private void DrawTextLines(SpriteBatch sprite, float scroll)
		{
			m_nLinesToShow = (int)Math.Ceiling(m_ConsoleRect.Height / m_TextSize.Y);
			float startY = m_ConsoleRect.Height - (m_nLinesToShow + 1) * m_TextSize.Y;
			int startIndex = GetTextIndex(m_CurrentTextIndex - m_nLinesToShow);

			for (int i = 0; i <= m_nLinesToShow; i++)
			{
				string str = m_Text[GetTextIndex(startIndex + i)];
				if(str != null)
				{
					Vector2 pos = new Vector2(10, startY + i * m_TextSize.Y);
					sprite.DrawString(m_Font, str, pos, Color.LightGreen);
				}
			}
		}

		private int GetTextIndex(int startIndex)
		{
			if (startIndex < 0)
			{
				startIndex += m_Text.Length;
			}

			return startIndex % m_Text.Length;
		}
	}
}